-
Notifications
You must be signed in to change notification settings - Fork 13.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Stabilize naked_functions
#134213
base: master
Are you sure you want to change the base?
Stabilize naked_functions
#134213
Conversation
Some changes occurred in src/doc/unstable-book/src/compiler-flags/sanitizer.md cc @rust-lang/project-exploit-mitigations, @rcvalle This PR modifies cc @jieyouxu rust-analyzer is developed in its own repository. If possible, consider making this change to rust-lang/rust-analyzer instead. cc @rust-lang/rust-analyzer Some changes occurred in compiler/rustc_codegen_cranelift cc @bjorn3 |
☔ The latest upstream changes (presumably #134395) made this pull request unmergeable. Please resolve the merge conflicts. |
6183807
to
ed0d0b9
Compare
ed0d0b9
to
ae2fa18
Compare
r? lang |
This probably needs a new lang FCP since the old one is probably outdated (the implementation of naked function has changed signficantly). |
Thanks for the thorough report @folkertdev! @rfcbot fcp merge |
Team member @tmandry has proposed to merge this. The next step is review by the rest of the tagged team members: Concerns:
Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns. |
Actually, @rust-lang/libs-api does this need your FCP? I think the path of |
catching up to some comments
Yes that is what I would argue :) from the edition guide
There are no soundness requirements to a naked function itself. The requirements are on the
Correct, that is tested here: rust/tests/ui/asm/naked-functions.rs Lines 79 to 81 in ed897d5
Sadly not. LLVM target features are also just made-up names that don't always map to the names that the assembler uses. E.g. the arm
That is my proposed course of action. So far nobody seems to really be against this approach, so if things stay that way I'll make a PR. |
And I guess we can't send the naked function "through" LLVM to let it do the translation? That might be a good feature request for them...
Sounds good to me. |
No that was the original design, but it was rejected for various reasons:
Some further context from the tracking issue: |
As they should. They have to deal with target feature names anyway for regular code. Anyway, I am mostly clueless here, just poking a bit in the dark to feel out the design space. @Amanieu knows a lot better than me how to make inline assembly work well. :) |
☔ The latest upstream changes (presumably #138450) made this pull request unmergeable. Please resolve the merge conflicts. |
ae2fa18
to
1687743
Compare
…eature-gate, r=Amanieu add `naked_functions_target_feature` unstable feature tracking issue: rust-lang#138568 tagging rust-lang#134213 rust-lang#90957 This PR puts `#[target_feature(/* ... */)]` on `#[naked]` functions behind its own feature gate, so that naked functions can be stabilized. It turns out that supporting `target_feature` on naked functions is tricky on some targets, so we're splitting it out to not block stabilization of naked functions themselves. See the tracking issue for more information and workarounds. Note that at the time of writing, the `target_features` attribute is ignored when generating code for naked functions. r? `@Amanieu`
…eature-gate, r=Amanieu add `naked_functions_target_feature` unstable feature tracking issue: rust-lang#138568 tagging rust-lang#134213 rust-lang#90957 This PR puts `#[target_feature(/* ... */)]` on `#[naked]` functions behind its own feature gate, so that naked functions can be stabilized. It turns out that supporting `target_feature` on naked functions is tricky on some targets, so we're splitting it out to not block stabilization of naked functions themselves. See the tracking issue for more information and workarounds. Note that at the time of writing, the `target_features` attribute is ignored when generating code for naked functions. r? ``@Amanieu``
Rollup merge of rust-lang#138570 - folkertdev:naked-function-target-feature-gate, r=Amanieu add `naked_functions_target_feature` unstable feature tracking issue: rust-lang#138568 tagging rust-lang#134213 rust-lang#90957 This PR puts `#[target_feature(/* ... */)]` on `#[naked]` functions behind its own feature gate, so that naked functions can be stabilized. It turns out that supporting `target_feature` on naked functions is tricky on some targets, so we're splitting it out to not block stabilization of naked functions themselves. See the tracking issue for more information and workarounds. Note that at the time of writing, the `target_features` attribute is ignored when generating code for naked functions. r? ``@Amanieu``
☔ The latest upstream changes (presumably #138791) made this pull request unmergeable. Please resolve the merge conflicts. |
1687743
to
02cff1f
Compare
The tracking issue: #138568 Looking at the other concerns, The current remaining concerns are then:
Ah, I misunderstood this earlier. What I meant is that we could have used llvm's native support for naked functions, which has the downsides that I and Amanieu mentioned. I think you propose to still use global assembly, but somehow inform the backend of the target features. That would be neat, but can't currently be done even in LLVM. |
Is there a practical reason to allow I think unless there is a specific need for it it would be best to disallow it (From an mostly outsider perspective, I'm not really familiar with the state of Rust ABI and the current state of naked functions). |
Linting on |
Sounds right. Thanks for filing the new tracking issue. @rfcbot resolve what-to-do-for-target-feature
They are. Thanks for adding these notes. The rationales and outcomes there seem right to me. @rfcbot resolve question-about-noreturn
These probably need to be discussed with the team. We'll take them up in a lang call. |
On the Not requiring that certainly makes sense to me, though, especially for |
OK. On the lang call today, we reviewed all of the concerns resolved above, and we worked through the two remaining items. Here's what we want to do. One, we don't want to stabilize naked functions with the "Rust" ABI as part of this stabilization. We'd like that (and all rustic ABIs) carved off into a separate feature flag and tracking issue. Then, if we find there's some use case for this that doesn't rely on details to which we're not willing to commit, we can later consider that on its own. One reason for this is caution due to Hyrum's law:
Because of the nature of naked functions, it's difficult to use them without relying on details of the ABI, and we don't want to later have this conversation when making changes to the Rust ABI:
By contrast, someone having to reach for nightly to do this sends the right signal. Two, we want to move the We had a good long and hearty discussion about this one looking at it from every angle. The deciding factor here is in thinking about the proper scope of the unsafe {
#[naked]
extern "sysv64" fn f() {
naked_asm! {
..
}
}
} That is, the author of the function needs to prove certain properties about the function as a whole, inclusive of and affected by that Therefore it makes sense to move the #[unsafe(naked)]
extern "sysv64" fn f() {
naked_asm! {
..
}
} Pleasingly, this also avoids some rightward drift. I'll go ahead and resolve the concerns as we've answered the questions here. @rfcbot resolve maybe-unsafe-attribute Please update the PR (and the Reference PR) accordingly and hand it back to me. @rustbot author |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
The final comment period, with a disposition to merge, as per the review above, is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. This will be merged soon. |
tracking issue: #90957
request for stabilization on tracking issue: #90957 (comment)
reference PR: rust-lang/reference#1689
Request for Stabilization
Two years later, we're ready to try this again. Even though this issue is already marked as having passed FCP, given the amount of time that has passed and the changes in implementation strategy, we should follow the process again.
Summary
The
naked_functions
feature has two main parts: the#[naked]
function attribute, and thenaked_asm!
macro.An example of a naked function:
When the
#[naked]
attribute is applied to a function, the compiler won't emit a function prologue or epilogue when generating code for this function. This attribute is analogous to__attribute__((naked))
in C. The use of this feature allows the programmer to have precise control over the assembly that is generated for a given function.The body of a naked function must consist of a single
naked_asm!
invocation, a heavily restricted variant of theasm!
macro: the only legal operands areconst
andsym
, and the only legal options areraw
andatt_syntax
. In lieu of specifying operands, thenaked_asm!
within a naked function relies on the function's calling convention to determine the validity of registers.Documentation
The Rust Reference: rust-lang/reference#1689
(Previous PR: rust-lang/reference#1153)
Tests
pub
,#[no_mangle]
and#[linkage = "..."]
work correctly for naked functionsnaked_asm!
, etcInteraction with other (unstable) features
fn_align
Combining
#[naked]
with#[repr(align(N))]
works well, and is tested e.g. hereIt's tested extensively because we do need to explicitly support the
repr(align)
attribute (and make sure we e.g. don't mistake powers of two for number of bytes).History
This feature was originally proposed in RFC 1201, filed on 2015-07-10 and accepted on 2016-03-21. Support for this feature was added in #32410, landing on 2016-03-23. Development languished for several years as it was realized that the semantics given in RFC 1201 were insufficiently specific. To address this, a minimal subset of naked functions was specified by RFC 2972, filed on 2020-08-07 and accepted on 2021-11-16. Prior to the acceptance of RFC 2972, all of the stricter behavior specified by RFC 2972 was implemented as a series of warn-by-default lints that would trigger on existing uses of the
naked
attribute; these lints became hard errors in #93153 on 2022-01-22. As a result, today RFC 2972 has completely superseded RFC 1201 in describing the semantics of thenaked
attribute.More recently, the
naked_asm!
macro was added to replace the earlier use of a heavily restrictedasm!
invocation. Thenaked_asm!
name is clearer in error messages, and provides a place for documenting the specific requirements of inline assembly in naked functions.The implementation strategy was changed to emitting a global assembly block. In effect, an extern function
is emitted as something similar to
The codegen approach was chosen over the llvm naked function attribute because:
Finally, there is now an allow list of compatible attributes on naked functions, so that e.g.
#[inline]
is rejected with an error. The#[target_feature]
attribute on naked functions was later made separately unstable, because implementing it is complex and we did not want to block naked functions themselves on how target features work on them. See also #138568.relevant PRs for these recent changes
#[naked]
: report incompatible attributes #127853naked_asm!
macro for use in#[naked]
functions #128651#[naked]
functions using global asm #128004naked_functions_target_feature
unstable feature #138570Various historical notes
noreturn
RFC 2972 mentions that naked functions
Instead of
asm!
, the current implementation mandates that the body contain a singlenaked_asm!
statement. Thenaked_asm!
macro is a heavily restricted version of theasm!
macro, making it easier to talk about and document the rules of assembly in naked functions and give dedicated error messages.For
naked_asm!
, the behavior of theasm!
'snoreturn
option is implicit. Thenoreturn
option means that it is UB for control flow to fall through the end of the assembly block. Withasm!
, this option is usually used for blocks that diverge (and thus have no return and can be typed as!
). Withnaked_asm!
, the intent is different: usually naked funtions do return, but they must do so from within the assembly block. Thenoreturn
option was used so that the compiler would not itself also insert aret
instruction at the very end.padding /
ud2
A
naked_asm!
block that violates the safety assumption that control flow must not fall through the end of the assembly block is UB. Because no return instruction is emitted, whatever bytes follow the naked function will be executed, resulting in truly undefined behavior. There has been discussion whether rustc should emit an invalid instruction (e.g.ud2
on x86) after thenaked_asm!
block to at least fail early in the case of an invalidnaked_asm!
. It was however decided that it is more useful to guarantee that#[naked]
functions NEVER contain any instructions besides those in thenaked_asm!
block.unresolved questions
None
r? @Amanieu
I've validated the tests on x86_64 and aarch64